package com.ungao.framework.web.context;

import com.ungao.framework.bytecode.AsmParameterNameLoader;
import com.ungao.framework.context.XmlPathConfigApplicationContext;
import com.ungao.framework.define.BeanDefinition;
import com.ungao.framework.scanner.AnnotationScanner;
import com.ungao.framework.web.annotation.RequestController;
import com.ungao.framework.web.annotation.RequestMapping;

import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * WEB应用上下文
 */
public class WebApplicationContext extends XmlPathConfigApplicationContext {

    /**
     * 请求地址映射方法
     */
    private final Map<String, Method> handlerMapping = new ConcurrentHashMap<>();

    /**
     * 请求地址映射参数
     */
    private final Map<String, Map<String, Parameter>> parameterMapping = new ConcurrentHashMap<>();

    /**
     * 方法参数获取工具
     */
    private final AsmParameterNameLoader parameterNameLoader = new AsmParameterNameLoader();


    public WebApplicationContext(String contextConfigLocation) {
        super(contextConfigLocation);
        try {
            this.initHandlerMapping();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取请求方法
     *
     * @param uri
     * @return
     */
    public Method getMethod(String uri) {
        return this.handlerMapping.get(uri);
    }

    /**
     * 获取参数信息
     *
     * @param uri
     * @return
     */
    public Map<String, Parameter> getParameters(String uri) {
        return this.parameterMapping.get(uri);
    }

    /**
     * 判断请求地址
     *
     * @param uri
     * @return
     */
    public boolean hasUri(String uri) {
        return this.handlerMapping.containsKey(uri);
    }

    /**
     * 容器默认不会扫描mvc模块下面的注解,所以需要加上
     *
     * @param annotations
     */
    @Override
    protected void initApplicationContext(AnnotationScanner annotations) {
        annotations.put(RequestController.class);
    }

    /**
     * 初始化请求地址映射
     */
    private void initHandlerMapping() throws IOException {
        for (Map.Entry<String, BeanDefinition> entry : beanFactory.entrySet()) {

            //获取bean定义信息
            BeanDefinition beanDefinition = entry.getValue();

            //接口不做任何处理
            if (beanDefinition.isInterface()) {
                continue;
            }

            //获取当前类元信息
            Class<?> clazz = entry.getValue().getOriginal().getClass();
            if (clazz.isAnnotationPresent(RequestController.class)) {

                String baseUrl = "";
                if (clazz.isAnnotationPresent(RequestMapping.class)) {
                    RequestMapping requestMapping = clazz.getAnnotation(RequestMapping.class);
                    baseUrl = requestMapping.value();
                }

                for (Method method : clazz.getMethods()) {
                    if (!method.isAnnotationPresent(RequestMapping.class)) {
                        continue;
                    }

                    RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
                    String url = ("/" + baseUrl + "/" + requestMapping.value()).replaceAll("/+", "/");

                    //请求地址映射方法
                    this.handlerMapping.putIfAbsent(url, method);

                    //请求地址映射参数
                    this.parameterMapping.putIfAbsent(url, this.parameterNameLoader.getParameterNames(method));
                    System.out.println("Mapped " + url + "," + method);
                }
            }
        }
    }
}
